#ifndef LIST_C
#define LIST_C
#include<iostream>
#include<stack>
#include<math.h>
#include<cctype>//为了引入isdigit（）函数
using namespace std;

stack<char> Op;//操作符栈
stack<double> Num;//操作数栈1 

/*传入一个字符型变量，判断其的优先级并将优先级返回*/ 
int level(char ch)
{
	switch(ch)
	{
		case'(':
			return 0;
		
		case'-':
		case'+':
			return 1;
		
		case'*':
		case'/':
		case'%': 
			return 2;
			
		case'^':
			return 3;
			
		case'!':
			return 4;
			
		case')':
			return 5;
	}
}


/*传入一个整型变量，计算其的阶乘并将其返回*/ 
int Take_the_order(int n)
{
	if(n >= 1)
	{
		return n*Take_the_order(n-1); 
	}
	else
	{
		return 1;
	}
}
/*
string delete_space(string &str)//传入一个后缀表达式，将其中的空格删去并返回 
{
	string str2;//用于储存转化后的表达式
	
	for(int i = 0; i < str.length(); i++)
	{
		if(str[i] != ' ')
		{
			str2 += str[i];
		}
	}
	cout << str2;
	return str2; 
}*/

/*传入一个字符串（中缀表达式），将其转变为后缀表达式并返回*/
string change(string &str1)
{
	string str2;//用于存储转变后的后缀表达式 
	int temp1 = 0;//用于判断字符是否为0~9之中的一个判断符,0为在数字外，1为在数字内。 
	int temp2 = 0;//用于判断负号表示的是正负还是运算 ，0为运算，1为正负 
	char c;//用于短暂储存字符串中的字符
	int num = 0;//可用于记录多位操作数 
	
	for(int i = 0; i < str1.length(); i++)//依次读取字符串
	{
	    c = str1[i];
		if(isdigit(c))//用于检查参数是否为十进制数，若参数为0~9则返回非0值，否则返回NULL
		{
			if(temp2 == 1)//如果判断前一负号代表正负，直接在后缀表达式的下一个操作数前加上负号 
			{
				str2 = str2 + '-';
				temp2 = 0; 
			}
			str2 = str2 + c;//如果是数字，则直接加入到str2中
			str2 = str2 + ' ';//此操作是为了将后缀表达式中的每一项都分割开来以便观察和读取
			temp1 = 1;//表示c这个字符在数字内 
		}
		else{ 
		    if(temp1 == 0 && c == '-' && str1[i-1] != ')')//如果当前字符是负号且上一个字符不是数字(不是反括号)，则判断当前负号为表达正负 
			{
			    temp2 = 1;//将temp2置1 
				continue;//跳出该次循环 
			}                                
			if(temp1 == 1 && c == '.')//若当前字符为'.’,且上一个字符在数字内，则这一小串字符判断为小数
			{
				str2 = str2 + '.';//将小数点加入后缀字符串中 
				continue;//直接跳出该次循环
			 }
	
		    if(c == '(')//如果当前字符为左括号，则将其直接压入操作符栈
			{
				Op.push(c); 
			}
			else if(c == ')')//如果当前字符为右括号，如果操作符栈不为空则直接将操作符栈中的元素出栈并将其加入到str2中，直到'('为止；
			{
				while(!Op.empty() && Op.top() != '(')
				{
					str2 = str2 + Op.top();
					str2 = str2 + ' ';//此操作是为了将后缀表达式中的每一项都分割开来以便观察和读取 
				
					Op.pop();
				}
				Op.pop();//将栈顶的'('出栈，不将其加入str2中 
			}
			else
			{
				while(true)
				{
					if(Op.empty() || Op.top() == '(')//如果操作符栈是为空或者当前操作符栈顶是'('时 
				    {
					    Op.push(c);//将当前字符直接压栈 
				    }
				else if(level(c) > level(Op.top()))//如果当前字符的优先级大于操作符栈顶的优先级 
				{
					Op.push(c);//将当前字符直接压栈 
				}
				else//如果当前字符的优先级小于等于操作符栈顶的优先级,则将操作符栈顶元素出栈并加入str2中，直到当前字符的优先级大于操作符栈顶的优先级 
				{
					str2 = str2 + Op.top();
					str2 = str2 + ' ';//此操作是为了将后缀表达式中的每一项都分割开来以便观察和读取 
					Op.pop();
					continue;
				 }
				break;  
				}
			}
			temp1 = 0;//表示当前字符不在数字内 
			temp2 = 0;
		}
	}
	while(!Op.empty())//当字符串读取完且操作符栈中还有剩余元素时，将剩余元素出栈并且将其加入str2中 
	{
		str2 = str2 + Op.top();
		str2 = str2 + ' ';//此操作是为了将后缀表达式中的每一项都分割开来以便观察 
		Op.pop();
	}
	return str2;//返回后缀表达式 
} 

void compute(string &str)//传入一个后缀表达式，对其进行运算并输出结果 
{
	int temp1 = 0;//(自定义)用于判断字符是否为0~9之中的一个判断符,0为在数字外，1为在数字内。 
	int temp2 = 0;//（自定义）用于判断后缀字符串是否包含小数，0为不包含小数，1为包含小数 
	int temp3 = 0;
	int temp4 = 0; 
	char c;//用于短暂储存字符串中的字符
	int num = 0;//用于读取数字 
	double count = 1.0;//用于小数的读取 
	
	for(int i = 0; i < str.length(); i++)//依次读取后缀表达式中的字符 
	{
		c = str[i];
		if(isdigit(c) || c == '.' )//用于检查参数是否为十进制数，若参数为0~9则返回非0值，否则返回NULL
		{
			if(isdigit(c))
			{
				num *= 10;//用于读取有十位数,百位数,千位数。。。。。。
				num += c - '0';//将字符转化为数字 
				temp1 = 1;//表示当前字符为数字 
				if(temp2 == 1)//表示当前字符是小数点后的字符，有多少位小数，就进行多少次这个语句 
				{
					count *= 10.0;
				}
			}
			if(c == '.')//如果当前字符是'.',则将 temp2置1，并直接退出该次循环 
			{
				temp2 = 1;
				continue; 
			}
		 }
		 else
		 {
		 	double result = num / count;//小数的计算 
		 	if(temp3 == 1 && temp1 ==  1)// 如果上个字符在数字内，且当前操作数前有代表着负数的负号 
		 	{
		 		result  = -1.0 * result;//将该操作数变为负的 
		 		temp3 = 0;//将temp3置为初始值 
			 }
			temp2 = 0;//能进行这一步骤说明已经读取完一个操作数，则将temp2置为初始值
		 	count = 1.0;//能进行这一步骤说明已经读取完一个操作数，则将count置为初始值;
			 
			 	if(c == '-' && isdigit(str[i+1])!=0)//如果当前字符为负号且下一个字符为数字（因为在中缀转后缀的过程中人为的加入空格，所以下一个字符是数字的负号代表正负，下一个字符不是数字的负号代表运算） 
		 	{
		 		temp3 = 1;//将temp3置1，代表这个负号代表着正负 
		 		continue;//退出该次循环 
			 }
			 
			if (temp1 == 1)//如果上一个字符在数字内，则将其之前的字符串所表示的操作数压入操作数栈 
			{
				Num.push(result);
				num = 0;//将num置为初始值； 
			}
			
			double x, y, z;//设计三个运算数；
			if(c != ' ')//因为在中缀转后缀时加入了空格，所以要排除当前字符是空格的情况 
			{
				if(c == '!')
				{
					y = Num.top();//乘阶运算只用一个操作数 
					Num.pop();
					
					if(y < 0)
					{
						cout << "小于0的数不能乘阶"  << endl;
						system("pause");
						return; 
					}
					
					int k = (int)y;	
					z = (double)Take_the_order(k);	//乘阶运算			
					Num.push(z);
					continue;
				}
				
				y = Num.top();//从运算数栈中取两个元素,注意顺序（顺序会影响减法和除法），后缀表达式中靠后的元素在栈中靠前 
				Num.pop();
				x = Num.top();
				Num.pop();
				
				switch(c)
				{
					case'+':
						z = x + y;
						Num.push(z);
						break;
					
					case'-':
						z = x - y;
						Num.push(z);
						break;
						
					case'*':
					    z = x * y;
						Num.push(z);
						break;
						
					case'/':
						if(y == 0)
						{
							cout << "除数为0，运算错误。" << endl;
							system("pause");
							return;
						} 
					    z = x / y;
						Num.push(z);
						break; 
						
					case'%':
					    z = fmod(x,y);//fmod函数，返回x除以y的余数 
						Num.push(z);
						break;
					
					case'^':
						z = 1.0;
					   for(int n = 0; n < y; n++)
					   {
					   	z *= x;
						}
						Num.push(z);
						break; 
				} 
			}
			temp1 = 0;//将temp1置0 
	    }
    }
	cout << "计算结果为：" << Num.top() << endl; 
	system("pause"); 

}


#endif
